<template>
  <div class="dataList" ref="dataListRef">
    <div class="row" v-for="(item, rowIndex) in dataList" :key="rowIndex">
      <!-- 辅助： 供复制粘贴 -->
      <div
        class="row_item_auxi"
        :style="{ zIndex: isShowAuxi ? 1 : -1 }"
        v-if="isShowAuxi"
      >
        <div
          v-for="cloumnIndex in 24"
          :key="cloumnIndex"
          @click="handleRowItemClick(rowIndex, cloumnIndex)"
          :class="[
            'row_item_auxi_item',
            'auxi_to_be_select',
            selectedItemIndex[0] === rowIndex &&
            selectedItemIndex[1] === cloumnIndex
              ? 'auxi_is_select'
              : '',
          ]"
        ></div>
      </div>
      <div
        :class="[
          'row_cloumn',
          rightSelectIndex === rowIndex ? 'selectRow' : '',
        ]"
        v-for="(it, cloumnIndex) in item.data"
        :key="cloumnIndex"
        :data-rowIndex="rowIndex"
      >
        <row-item
          :x_start="it.x_start"
          :x_end="it.x_end"
          :name="it.name"
          :rowHeight="rowHeight"
          @currentRow_update="
            (s, e) => {
              handleUpdate(s, e, rowIndex, cloumnIndex);
            }
          "
          @enjambment_update="
            (s, e, rowNum) => {
              handleEnjambment(s, e, rowNum, rowIndex, cloumnIndex);
            }
          "
          @select_update="
            (select) => {
              selectItem = select;
            }
          "
          @size_update="
            (s, e) => {
              handleUpdate(s, e, rowIndex, cloumnIndex);
            }
          "
        />
      </div>
    </div>
    <custom-menu
      ref="customMenuRef"
      @cancle="handleContextMenuCancle"
      @submit="handleContextMenuSubmit"
    />
  </div>
  <el-button @click="getData">获取最新数据</el-button>
</template>

<script setup>
import { computed, onMounted, ref, watch } from "vue";
import rowItem from "./rowItem.vue";
import { ElMessage, ElNotification } from "element-plus";
import customMenu from "./customMenu.vue";
import dayjs from "dayjs";

const props = defineProps({
  rowItemWidth: {
    type: Number,
    default: 60,
  },
  rowHeight: {
    type: Number,
    default: 50,
  },
  curTime: {
    type: String,
    default: "",
  },
});

onMounted(async () => {
  // 获取数据
  await getDataList();
  // 通过时间更新位置信息
  update_position_by_time();
  initClipboard();
  registerCopy();
  registerPaste();
  registerContextmenu();
});

const dataListRef = ref(null);
let selectItem = ref(null);
const customMenuRef = ref(null);
let rightSelectIndex = ref(undefined);
const _rowItemWidth = computed(() => props.rowItemWidth + "px");
const _rowWidth = computed(() => props.rowItemWidth * 24 + "px");
const _rowHeight = computed(() => props.rowHeight + "px");
let dataList = ref([]);

// 是否显示辅助区（用来复制粘贴时选中）
const isShowAuxi = ref(false);
// 当前选中的辅助区索引
let selectedItemIndex = ref([]);

const getDataList = () => {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      dataList.value = [
        {
          name: "test01",
          data: [
            {
              startTime: "2024-10-09 00:00:00",
              endTime: "2024-10-09 02:00:00",
              x_start: 60,
              x_end: 200,
              name: "张三-1",
            },
            {
              startTime: "2024-10-09 08:00:00",
              endTime: "2024-10-09 09:00:00",
              x_start: 320,
              x_end: 500,
              name: "张三-2",
            },
          ],
        },
        {
          name: "test02",
          data: [
            {
              startTime: "2024-10-09 00:00:00",
              endTime: "2024-10-09 02:00:00",
              x_start: 60,
              x_end: 200,
              name: "张三-3",
            },
            {
              startTime: "2024-10-09 08:00:00",
              endTime: "2024-10-09 09:00:00",
              x_start: 250,
              x_end: 300,
              name: "张三-4",
            },
          ],
        },
        {
          name: "test02",
          data: [
            {
              startTime: "2024-10-09 00:00:00",
              endTime: "2024-10-09 02:00:00",
              x_start: 69,
              x_end: 200,
              name: "张三-5",
            },
            {
              startTime: "2024-10-09 08:00:00",
              endTime: "2024-10-09 09:00:00",
              x_start: 300,
              x_end: 360,
              name: "张三-6",
            },
          ],
        },
      ];
      resolve();
    }, 2000);
  });
};

// 时间转相对位置
const timeToPosition = (basisTime, startTime, endTime) => {
  // 基准时间转时间戳
  const basis_time = new Date(basisTime).getTime();
  // 开始时间转时间戳
  const start_time = new Date(startTime).getTime();
  // 结束时间转时间戳
  const end_time = new Date(endTime).getTime();
  // 时间戳差值
  const basis_to_start = start_time - basis_time;
  const start_to_end = end_time - start_time;
  const basis_to_end = end_time - basis_time;
  // 一天时间戳
  let totalTime = 24 * 60 * 60 * 1000;
  // 容器总长
  let totalWidth = props.rowItemWidth * 24;
  // 相对位置
  let position_basis_to_start = (basis_to_start / totalTime) * totalWidth;
  let position_basis_to_end = (basis_to_end / totalTime) * totalWidth;
  let position_start_to_end = (start_to_end / totalTime) * totalWidth;
  return [
    position_basis_to_start,
    position_basis_to_end,
    position_start_to_end,
  ];
};

// 通过时间更新位置信息
const update_position_by_time = () => {
  dataList.value.forEach((item) => {
    item.data = item.data.map((it) => {
      const { startTime, endTime } = it;
      const [x_start, x_end] = timeToPosition(
        props.curTime,
        startTime,
        endTime
      );
      return {
        ...it,
        x_start,
        x_end,
      };
    });
  });
};

// 位置转时间
const positionToTime = (basisTime, x_start, x_end) => {
  let sUnix = parseInt(dayjs(basisTime).format("x"));
  let eUnix = parseInt(dayjs(basisTime).add(1, "day").format("x"));
  let totalWidth = props.rowItemWidth * 24;
  let sTime = dayjs((eUnix - sUnix) * (x_start / totalWidth) + sUnix).format(
    "YYYY-MM-DD HH:mm:ss"
  );
  let eTime = dayjs((eUnix - sUnix) * (x_end / totalWidth) + sUnix).format(
    "YYYY-MM-DD HH:mm:ss"
  );
  return [sTime, eTime];
};

// 通过位置信息更新时间
const update_time_by_position = () => {
  dataList.value.forEach((item, index) => {
    item.data = item.data.map((it) => {
      const { x_start, x_end } = it;
      const [startTime, endTime] = positionToTime(
        props.curTime,
        x_start,
        x_end
      );
      return {
        ...it,
        startTime,
        endTime,
      };
    });
  });
};

const getData = () => {
  console.log("最新数据", dataList.value);
};

// 清空剪切板数据
const initClipboard = async () => {
  try {
    let clipboard = await navigator.clipboard.readText();
    clipboard && (await navigator.clipboard.writeText(""));
  } catch (err) {
    console.log("异常", err.message);
  }
};

// 注册copy事件
const registerCopy = () => {
  dataListRef.value.addEventListener("copy", async (e) => {
    e.preventDefault();
    console.log("复制内容", selectItem.value);
    if (!selectItem.value) {
      ElMessage.warning("请选择需要复制的项");
      return;
    }
    await navigator.clipboard.writeText(JSON.stringify(selectItem.value));
    ElNotification({
      title: "提示",
      message: `当前用户： ${selectItem.value.name}信息复制成功`,
      duration: 3000,
      type: "success",
    });
    // 复制成功之后显示粘贴辅助
    isShowAuxi.value = true;
  });
};

// 注册粘贴事件
const registerPaste = () => {
  dataListRef.value.addEventListener("paste", (e) => {
    e.preventDefault();
    const clipboard = e.clipboardData || window.clipboardData;
    console.log("粘贴数据", clipboard.getData("text"));
    const clipboardData = clipboard.getData("text");
    if (!clipboardData) {
      ElMessage.warning("请先选择需要复制的项，进行复制操作");
      return;
    }
    if (selectedItemIndex.value.length === 0) {
      ElMessage.warning("请先选择需要粘贴的位置");
      return;
    }
    const _clipboardData = JSON.parse(clipboardData);
    const [rowIndex, cloumnIndex] = selectedItemIndex.value;
    const { name } = _clipboardData;
    console.log("将要粘贴的数据", _clipboardData, selectedItemIndex.value);
    // 将复制的数据追加到数据列表中
    dataList.value[rowIndex].data.push({
      x_start:
        (cloumnIndex - 1 >= 0 ? cloumnIndex - 1 : 0) * props.rowItemWidth,
      x_end: cloumnIndex * props.rowItemWidth,
      name,
    });
    // 通过位置信息更新时间
    update_time_by_position();
    // 粘贴成功之后隐藏粘贴辅助
    isShowAuxi.value = false;
    // 清空辅助选中数据
    selectedItemIndex.value = [];
    // 清空剪切板,清除上次选中复制的数据（复制一次粘贴一次： 打开/复制一次粘贴多次：注释）
    initClipboard();
    selectItem.value = null;
  });
};

// 注册右击事件监听
const registerContextmenu = () => {
  dataListRef.value.addEventListener("contextmenu", function (event) {
    event.preventDefault(); // 阻止默认右键菜单
    console.log("**********", customMenuRef.value);
    // 设置菜单的位置
    customMenuRef.value.$el.style.left = event.pageX + "px";
    customMenuRef.value.$el.style.top = event.pageY + "px";
    // 显示菜单
    customMenuRef.value.$el.style.display = "block";
    console.log("右击", event.pageY, event);
    rightSelectIndex.value = parseInt(event.target.dataset.rowindex);
  });
  dataListRef.value.addEventListener("click", function () {
    // 点击页面其他地方时隐藏自定义菜单
    customMenuRef.value.$el.style.display = "none";
    rightSelectIndex.value = undefined;
  });
};

// 右击确认
const handleContextMenuSubmit = (data) => {
  const { startTime, endTime, userName } = data;
  dataList.value[rightSelectIndex.value].data.push({
    startTime: `${props.curTime.split(" ")[0]} ${startTime}:00`,
    endTime: `${props.curTime.split(" ")[0]} ${endTime}:00`,
    x_start: "",
    x_end: "",
    name: userName,
  });
  update_position_by_time();
  console.log("右击确认", dataList.value[rightSelectIndex.value]);
  handleContextMenuCancle();
};

// 右击取消
const handleContextMenuCancle = () => {
  customMenuRef.value.$el.style.display = "none";
};

const handleRowItemClick = (rowIndex, cloumnIndex) => {
  selectedItemIndex.value[0] === rowIndex &&
  selectedItemIndex.value[1] === cloumnIndex
    ? (selectedItemIndex.value = [])
    : (selectedItemIndex.value = [rowIndex, cloumnIndex]);
};

const handleUpdate = (start, end, rowIndex, cloumnIndex) => {
  dataList.value[rowIndex].data[cloumnIndex].x_start = start;
  dataList.value[rowIndex].data[cloumnIndex].x_end = end;
  // 通过位置信息更新时间
  update_time_by_position();
};

// 跨行逻辑(向上： 当前拖动元素下边缘在存放容器上方才能拖进去，向下: 只有当前拖动元素上边缘在存放容器下方才能拖进去)
const handleEnjambment = (start, end, rowNum, rowIndex, cloumnIndex) => {
  // 跨行移除当前行
  if (
    (rowNum > 0 && rowNum + rowIndex + 1 > dataList.value.length) ||
    (rowNum < 0 && rowIndex + 1 - Math.abs(rowNum) < 0)
  ) {
    // 向上/向下超出整体容器范围
    return;
  }
  let item = dataList.value[rowIndex].data.splice(cloumnIndex, 1)[0];
  item.x_start = start;
  item.x_end = end;
  dataList.value[rowIndex + rowNum].data.push(item);
  // 通过位置信息更新时间
  update_time_by_position();
};
</script>

<style lang="scss" scoped>
.dataList {
  .row {
    position: relative;
    width: v-bind(_rowWidth);
    height: v-bind(_rowHeight);
    box-sizing: border-box;
    border: 1px solid #ccc;
    border-top: none;
    .row_item_auxi {
      position: absolute;
      left: -1px;
      top: 0;
      display: flex;
      .row_item_auxi_item {
        position: relative;
        width: v-bind(_rowItemWidth);
        height: v-bind(_rowHeight);
        border-right: 1px solid #ccc;
        border-bottom: 1px solid #ccc;
        box-sizing: border-box;
        cursor: pointer;
      }
      .row_item_auxi_item:first-child {
        border-left: 1px solid #ccc;
      }
      .auxi_to_be_select {
        position: relative;
        width: v-bind(_rowItemWidth);
        height: v-bind(_rowHeight);
      }
      .auxi_to_be_select::after {
        content: "粘贴在此";
        font-size: 10px;
        display: flex;
        justify-content: center;
        align-items: center;
        position: absolute;
        top: 0;
        left: 0;
        width: calc(v-bind(_rowItemWidth));
        height: calc(v-bind(_rowHeight) - 3px * 2);
        margin: 3px 0;
        background-color: #f0f0f0;
        box-sizing: border-box;
        border: 1px dashed #ccc;
      }
      .auxi_is_select {
        position: relative;
        width: v-bind(_rowItemWidth);
        height: v-bind(_rowHeight);
      }
      .auxi_is_select::after {
        content: "";
        position: absolute;
        top: 0;
        left: 0;
        width: calc(v-bind(_rowItemWidth));
        height: calc(v-bind(_rowHeight) - 3px * 2);
        margin: 3px 0;
        background-color: blue;
        box-sizing: border-box;
        border: 2px dashed #d80808;
      }
    }
    .row_cloumn {
      position: absolute;
      top: 0;
      left: -1px;
      width: v-bind(_rowWidth);
      height: calc(v-bind(_rowHeight) - 5px * 2);
      margin: 5px 0;
      background-color: #f0f0f0;
      border: 1px solid #ccc;
      box-sizing: border-box;
      box-shadow: 0 0 2px #ccc;
    }
    .selectRow {
      box-shadow: 0 0 8px #1890ff;
      transition: all 0.3s;
    }
  }
}
</style>
